﻿/************************************************************************

 This file is part of "10 Second Tim".

 "10 Second Tim" is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 "10 Second Tim" is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with "10 Second Tim".  If not, see <http://www.gnu.org/licenses/>.

************************************************************************/

// All code (c)2013 Scott Bevin. all rights reserved

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LDE;
using LDE.Input;
using LudumDare27.Games.Game_1;
using LudumDare27.GameScreens;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace LudumDare27.Games
{
	public class GameplayIntroScreen : GameScreen
	{
		private Camera m_cam;
		private SpriteFont computerFont;

		private string[ ] compStrings = new string[ 4 ];

		public Character m_playerchar = null;

		private Terrain m_terrain = null;

		private InputTrigger m_jumpInput = new InputTrigger( "Jump" );
		private InputTrigger m_computerTrigger = new InputTrigger( "CompOn" );

		private WhiteFadeScreen whiteFadeScreen = null;

		private ScreenBorder border;

		private float levelTimer = 0.0f;

		private int Level;
		private List<Sprite> m_scenerysprites = new List<Sprite>( );

		private string[ ] hintStrings = new string[ ]
		{
			"* 12/07/13 - An unknown issue with MegaCalc has caused Garry the intern to vanish. *",
			"* 13/07/13 - Garry keeps reappearing randomly. He looks different. *",
			"* 14/07/13 - Garry continues to appear randomly, the programmers are starting to get spooked. *",
			"* 27/07/13 - Garry has not reappeared for a while, presumed missing without permission. Bonus will be docked. *",
			"* 08/08/13 - Engineers are working to restore MegaCalc. *",
			"* 14/08/13 - 4 QA testers have now vanished while attempting to find easier reproduction steps. *",
			"* 20/08/13 - The fault has been traced to a NULL pointer causing recursion so deep it tore a hole in reality. *",
			"* 23/08/13 - Patch applied to MegaCalc. Engineers are 95% certain it should work with 32% probability. *",
			"* 26/08/13 - A new intern, Tim, has been hired to apply and test the patch. *",
		};

		private Vector2 hintPos;
		private SpriteFont hintFont;
		private int currentHintString = 0;
		private const int numHintStrings = 9;
		private float hintStringtimer = 0.0f;

		private bool computerOn = false;
		private bool computerError = false;
		private float cmpTimerTotal = 0.0f;
		private float cmpTimer = 0.0f;
		private int loadcnt = 0;

		private bool EndScreen = false;

		private GameScreen nextScreen;

		private SoundEffect computerBeeps;
		private SoundEffectInstance beepsInstance;

		private SoundEffect alarmSfx;
		private SoundEffectInstance alarmSfxInstance;

		private SoundEffect whiteNoiseSfx;
		private SoundEffectInstance whiteNoiseSfxInstance;

		private SoundEffect useComputerSfx;
		private SoundEffect compErrorSfx;

		public GameplayIntroScreen( bool endScreen, int level )
			: base( true )
		{
			Level = level;
			EndScreen = endScreen;
		}

		private Song backgroundMusic;

		override public void OnAdded( )
		{
			backgroundMusic = ( (LD27Game)Game ).PickSong( ContentManager );

			if ( EndScreen )
			{
				MediaPlayer.Play( backgroundMusic );
				MediaPlayer.IsRepeating = true;
			}

			useComputerSfx = ContentManager.Load<SoundEffect>( "Sfx/UseComputer" );
			compErrorSfx = ContentManager.Load<SoundEffect>( "Sfx/ComputerError" );

			computerBeeps = ContentManager.Load<SoundEffect>( "Sfx/Computer" );
			beepsInstance = computerBeeps.CreateInstance( );
			beepsInstance.IsLooped = true;
			beepsInstance.Play( );

			alarmSfx = ContentManager.Load<SoundEffect>( "Sfx/Alarm" );
			alarmSfxInstance = alarmSfx.CreateInstance( );
			alarmSfxInstance.IsLooped = true;
			alarmSfxInstance.Play( );

			whiteNoiseSfx = ContentManager.Load<SoundEffect>( "Sfx/AboutToTrans" );
			whiteNoiseSfxInstance = whiteNoiseSfx.CreateInstance( );
			whiteNoiseSfxInstance.IsLooped = true;
			whiteNoiseSfxInstance.Play( );

			hintFont = ContentManager.Load<SpriteFont>( "Fonts/HintFont" );

			border = new ScreenBorder( ContentManager );
			computerFont = ContentManager.Load<SpriteFont>( "Fonts/CompFont" );
			Random rnd = new Random( );

			if ( EndScreen )
			{
				compStrings[ 0 ] = "Mega Calc v0.2b";
				compStrings[ 1 ] = "SYS ERR";
				compStrings[ 2 ] = "0xDEADBEEF";
				compStrings[ 3 ] = "Press X To Turn Off";
			}
			else
			{
				compStrings[ 0 ] = "Mega Corp";
				compStrings[ 1 ] = "Mega Calc v0.2b";
				compStrings[ 2 ] = "";
				compStrings[ 3 ] = "Press X To Turn On";
			}

			m_cam = new Camera( Game.GraphicsDevice.PresentationParameters.BackBufferWidth,
				Game.GraphicsDevice.PresentationParameters.BackBufferHeight );
			m_cam.Zoom = 1.25f;

			//if ( EndScreen )
			m_playerchar = new Character( ContentManager.Load<Texture2D>( "Img/Chars/Garry" ), ContentManager );

			// 			else
			// 				m_playerchar = new Character( ContentManager.Load<Texture2D>( "Img/Chars/Tim" ), ContentManager );

			// provide constant grav
			m_playerchar.Acceleration.Y = Defs.IntroGame.Gravity;
			m_playerchar.Position.X = 1200.0f;
			m_cam.Position = m_cam.TargetPosition = m_playerchar.Position;

			m_terrain = new Terrain( this, 50, Defs.Game4.TileWidth, true );

			m_cam.Position = m_cam.TargetPosition = m_playerchar.Position;
			m_cam.Position.Y = m_cam.TargetPosition.Y = m_cam.TargetPosition.Y - 100.0f;

			hintPos = m_playerchar.Position;
			hintPos.Y = -200.0f;

			m_jumpInput.Add( Buttons.A ).Add( Keys.W ).Add( Keys.Up ).Add( Keys.Space );
			m_computerTrigger.Add( Buttons.X ).Add( Keys.X );

			// Add scenery
			Sprite ns = new Sprite( ContentManager.Load<Texture2D>( "Img/MCSign" ), 1 );
			ns.Pos = new Vector2( 1000.0f, -100.0f );
			m_scenerysprites.Add( ns );

			ns = new Sprite( ContentManager.Load<Texture2D>( "Img/EmployeeOfTheMonth" ), 1 );
			ns.Pos = new Vector2( 2000.0f, -100.0f );
			m_scenerysprites.Add( ns );

			if ( EndScreen )
			{
				ns = new Sprite( ContentManager.Load<Texture2D>( "Img/gameLogo" ), 1 );
				ns.Pos = new Vector2( 3000.0f, -ns.origin.Y + m_playerchar.m_sprite.origin.Y );
				m_scenerysprites.Add( ns );
			}
			else
			{
				ns = new Sprite( ContentManager.Load<Texture2D>( "Img/gameLogo2" ), 1 );
				ns.Pos = new Vector2( 3000.0f, -ns.origin.Y + m_playerchar.m_sprite.origin.Y );
				m_scenerysprites.Add( ns );
			}

			ns = new Sprite( ContentManager.Load<Texture2D>( "Img/ShelfOfWonders" ), 1 );
			ns.Pos = new Vector2( 4000.0f, -ns.origin.Y + m_playerchar.m_sprite.origin.Y );
			m_scenerysprites.Add( ns );

			ns = new Sprite( ContentManager.Load<Texture2D>( "Img/MegaComp" ), 1 );
			ns.Pos = new Vector2( 5000.0f, -ns.origin.Y + m_playerchar.m_sprite.origin.Y );
			m_scenerysprites.Add( ns );

			if ( EndScreen )
			{
				//m_cam.Rotation = m_cam.TargetRotation = (float)( Math.PI * 2.0f * rnd.NextDouble( ) );
				m_cam.Zoom = 2.0f;
				computerError = true;
			}

			base.OnAdded( );
		}

		override public void Update( float dt )
		{
			whiteNoiseSfxInstance.Volume = 0.0f;

			if ( computerError )
			{
				if ( computerError && m_playerchar.Position.X < 3500.0f && !EndScreen )
				{
					whiteNoiseSfxInstance.Volume = MathHelper.Clamp( ( ( 3500.0f - m_playerchar.Position.X ) / 1000.0f ), 0.0f, 1.0f );
				}
			}

			if ( m_playerchar.Position.X > 3500.0f )
			{
				alarmSfxInstance.Volume = 0.0f;

				if ( computerError )
				{
					alarmSfxInstance.Volume = MathHelper.Clamp( 1.0f - ( ( 5000.0f - m_playerchar.Position.X ) / 1500.0f ), 0.0f, 1.0f );
				}

				beepsInstance.Volume = MathHelper.Clamp( 1.0f - ( ( 5000.0f - m_playerchar.Position.X ) / 1500.0f ), 0.0f, 1.0f );
			}
			else
			{
				alarmSfxInstance.Volume = 0.0f;
				beepsInstance.Volume = 0.0f;
			}

			levelTimer += dt;

			if ( !EndScreen )
				levelTimer = 0.0f;

			if ( levelTimer > 3.0f )
			{
				whiteNoiseSfxInstance.Volume = MathHelper.Clamp( 1.0f - ( ( 10.0f - levelTimer ) / 3.0f ), 0.0f, 1.0f );
			}

			if ( levelTimer < 10.0f )
			{
				hintStringtimer += dt;

				if ( hintStringtimer > 4.0f )
				{
					hintStringtimer = 0.0f;
					++currentHintString;

					hintPos = m_playerchar.Position;
					hintPos.Y = -200.0f;
				}

				if ( computerOn )
				{
					cmpTimerTotal += dt;
					cmpTimer += dt;

					if ( cmpTimer > ( EndScreen ? 1.0f : ( ( ( cmpTimerTotal < 3.0f ) ? 0.5f : 0.1f ) ) ) )
					{
						cmpTimer = 0.0f;

						for ( int i = 0; i < 3; ++i )
							compStrings[ i ] = compStrings[ i + 1 ];

						++loadcnt;

						if ( EndScreen )
						{
							string[ ] endingStrings = new string[ ]
							{
								"Shutting Down",
								"Shutting Down",
								"Thanks For Playing",
								"A gameXcore game",
								"Scott Bevin",
								"gameXcore.co.uk",
								"@gameXcore",
								"Please vote!",
							};

							if ( loadcnt >= 8 )
								loadcnt = 0;

							compStrings[ 3 ] = endingStrings[ loadcnt ];
						}
						else
						{
							if ( cmpTimerTotal < 3.0f )
							{
								compStrings[ 3 ] = "Loading: " + loadcnt.ToString( );
							}
							else
							{
								compStrings[ 3 ] = "Error: 0x" + ( new Random( ).Next( 9999 ).ToString( ) );

								if ( !computerError )
								{
									if ( m_playerchar.Position.X > 4500.0f )
									{
										compErrorSfx.Play( 1.0f - ( ( 5000.0f - m_playerchar.Position.X ) / 500.0f ), 1.0f, 1.0f );
									}

									computerError = true;

									hintPos = m_playerchar.Position;
									hintPos.Y = -200.0f;
								}
							}
						}
					}
				}

				if ( m_playerchar.Dead )
					levelTimer = 0.0f;

				InputHandler input = Player.Get.GetInput( this );

				if ( input != null && !m_playerchar.Dead )
				{
					if ( input.IsPressed( m_jumpInput ) != null )
					{
						m_playerchar.Jump( );
						m_playerchar.CurrentAnim = null;
					}

					if ( input.IsTapped( m_computerTrigger ) != null && m_playerchar.Position.X > 4800 && m_playerchar.Position.X < 5100 )
					{
						computerOn = true;

						if ( m_playerchar.Position.X > 4500.0f )
						{
							useComputerSfx.Play( 1.0f - ( ( 5000.0f - m_playerchar.Position.X ) / 500.0f ), 1.0f, 1.0f );
						}

						m_scenerysprites[ 2 ] = new Sprite( ContentManager.Load<Texture2D>( "Img/gameLogo" ), 1 );
						m_scenerysprites[ 2 ].Pos = new Vector2( 3000.0f, -m_scenerysprites[ 2 ].origin.Y + m_playerchar.m_sprite.origin.Y );

						if ( EndScreen )
						{
							MediaPlayer.Stop( );

							computerError = false;
							m_cam.TargetRotation = 0.0f;

							levelTimer = 0.0f;
							compStrings[ 3 ] = "Shutting Down.";
						}
					}

					m_playerchar.Velocity.X = input.GetStickVals( ).X * Defs.IntroGame.BaseMoveSpeed;
				}

				m_playerchar.Update( dt, m_playerchar.Dead ? 1000.0f : m_terrain.GetGroundHeight( m_playerchar ), false );
				if ( m_playerchar.Position.X < 250.0f )
				{
					m_playerchar.Position.X = 250.0f;
					m_playerchar.Velocity.X = 0.0f;
					m_playerchar.CurrentAnim = null;
				}
				else if ( m_playerchar.Position.X > 5000 )
				{
					m_playerchar.Position.X = 5000;
					m_playerchar.Velocity.X = 0.0f;
					m_playerchar.CurrentAnim = null;
				}

				if ( computerError && m_playerchar.Position.X < 2500.0f && !EndScreen )
				{
					if ( whiteFadeScreen == null )
					{
						whiteFadeScreen = new WhiteFadeScreen( );
						nextScreen = ( (LD27Game)Game ).ChooseNextGame( this, Level + 1 );
						GameScreenManager.AddGameScreen( whiteFadeScreen, null, GameScreenManager.AddGameScreenData.PositioningOptions.OnTop );
					}
				}

				if ( !m_playerchar.Dead )
				{
					m_cam.TargetPosition = m_playerchar.Position;
					m_cam.TargetPosition.Y = m_cam.TargetPosition.Y - 100.0f;
				}

				m_cam.Update( dt );

				if ( !m_terrain.CharSafe( m_playerchar ) || m_playerchar.Dead )
				{
					if ( !m_playerchar.Dead )
					{
						m_playerchar.Kill( );
						m_playerchar.Velocity = Vector2.Zero;
						m_playerchar.Velocity.Y = -360.0f;
					}
					else if ( m_playerchar.Position.Y > 300.0f )
					{
						if ( whiteFadeScreen == null )
						{
							whiteFadeScreen = new WhiteFadeScreen( );
							nextScreen = ( (LD27Game)Game ).ChooseNextGame( this, Level + 1 );
							GameScreenManager.AddGameScreen( whiteFadeScreen, null, GameScreenManager.AddGameScreenData.PositioningOptions.OnTop );
						}
					}
				}
			}
			else
			{
				if ( whiteFadeScreen == null )
				{
					whiteFadeScreen = new WhiteFadeScreen( );

					if ( !EndScreen || !computerOn )
						nextScreen = ( (LD27Game)Game ).ChooseNextGame( this, Level + 1 );
					else
						nextScreen = new GameOverScreen( Level, true );

					GameScreenManager.AddGameScreen( whiteFadeScreen, null, GameScreenManager.AddGameScreenData.PositioningOptions.OnTop );
				}
			}

			if ( whiteFadeScreen != null && whiteFadeScreen.State == WhiteFadeScreen.States.FadedIn )
			{
				whiteFadeScreen.FadeOut( );

				GameScreenManager.AddGameScreen( nextScreen, whiteFadeScreen, GameScreenManager.AddGameScreenData.PositioningOptions.BelowRef );

				this.KillScreen = true;
			}

			base.Update( dt );
		}

		override public void Render( float dt, GraphicsDevice gd, SpriteBatch sprites )
		{
			sprites.Begin( SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, null, m_cam.GetWorldMatrix( ) );

			foreach ( Sprite s in m_scenerysprites )
				s.Render( sprites, s.Pos );

			for ( int i = 0; i < 4; ++i )
			{
				sprites.DrawString( computerFont, compStrings[ i ],
					new Vector2( 4886.0f, -110.0f + ( i * 16.0f ) ), Color.Green );
			}

			m_terrain.Render( sprites, m_playerchar );

			m_playerchar.Render( sprites );

			if ( currentHintString < numHintStrings || computerError )
			{
				float alpha = 1.0f;

				if ( hintStringtimer < 1.0f )
					alpha = 1.0f;
				if ( hintStringtimer > 3.0f )
					alpha = 4.0f - hintStringtimer;

				if ( computerError || ( EndScreen && !computerOn ) )
				{
					if ( ( EndScreen && !computerOn ) )
					{
					}
					else
					{
						Vector2 measure = hintFont.MeasureString( "** Warning: Error with MegaComp, please evacuate! **" );
						measure *= 0.5f;

						if ( hintPos.X - measure.X < 250.0f )
							hintPos.X = 250.0f + measure.X;
						if ( hintPos.X + measure.X > 5000.0f )
							hintPos.X = 5000.0f - measure.X;

						sprites.DrawString( hintFont, "** Warning: Error with MegaComp, please evacuate! **", hintPos, new Color( 1.0f, 0.0f, 0.0f, alpha ), 0.0f, measure, 1.0f, SpriteEffects.None, 1.0f );
					}
				}
				else
				{
					Vector2 measure = hintFont.MeasureString( hintStrings[ currentHintString ] );
					measure *= 0.5f;

					if ( hintPos.X - measure.X < 250.0f )
						hintPos.X = 250.0f + measure.X;
					if ( hintPos.X + measure.X > 5000.0f )
						hintPos.X = 5000.0f - measure.X;

					sprites.DrawString( hintFont, hintStrings[ currentHintString ], hintPos, new Color( 0.0f, 0.0f, 0.0f, alpha ), 0.0f, measure, 1.0f, SpriteEffects.None, 1.0f );
				}
			}

			sprites.End( );

			border.Render( gd, sprites );

			base.Render( dt, gd, sprites );
		}

		override public void OnRemoved( )
		{
#if SILVERLIGHT
			whiteNoiseSfxInstance.Stop(  );
			alarmSfxInstance.Stop(  );
			beepsInstance.Stop(  );
#else
			whiteNoiseSfxInstance.Stop( true );
			alarmSfxInstance.Stop( true );
			beepsInstance.Stop( true );
#endif

			base.OnRemoved( );
		}
	}
}